﻿#include "WidgetComClient.h"
#include <QFormLayout>
#include <QLabel>
#include <QInputDialog>
#include <QSerialPortInfo>
#include <QMessageBox>
#pragma execution_character_set("utf-8")

WidgetComClient::WidgetComClient(const QString &title, QWidget *parent):QGroupBox(title,parent)
{
    setupUI();
    initConnection();
    mMapComClient.clear();
}

void WidgetComClient::addComClient(ComBase *client)
{
    if(mMapComClient.contains(client->mConfig.name))
        return;
    mMapComClient.insert(client->mConfig.name, client);
    cbboxComNameList->addItem(client->mConfig.name);
    cbboxComNameList->setCurrentText(client->mConfig.name);
    connect(client, &ComBase::sigStateChanged, this, [&](const ComState& state){
        if(cbboxComNameList->currentText() == mMapComClient.value(cbboxComNameList->currentText())->mConfig.name){
            txtedtDataRev->append(ComBase::mapComStateText.value(state));
        }
    });
    connect(client, &ComBase::sigReceiveData, this, [&](const QByteArray& data){
        if(cbboxComNameList->currentText() == mMapComClient.value(cbboxComNameList->currentText())->mConfig.name){
            if(chkboxIsDisplayData->isChecked()){
                if(chkboxIsDisplayHex->isChecked()){
                    txtedtDataRev->append(data.toHex().toUpper());
                } else {
                    txtedtDataRev->append(data.data());
                }
            }
        }
    });
    connect(client, &ComBase::sigMsg, this, [&](const QString& str){
        if(cbboxComNameList->currentText() == mMapComClient.value(cbboxComNameList->currentText())->mConfig.name){
            txtedtDataRev->append(str);
        }
    });
    connect(this, &WidgetComClient::sigConfigChanged, client, &ComBase::onConfigChanged);
    connect(this, &WidgetComClient::sigWriteData, client, QOverload<const QString&>::of(&ComBase::onWrite));
}

void WidgetComClient::setupUI()
{
    mLayout = new QHBoxLayout();
    this->setLayout(mLayout);
    setupConfigUI();
    setupSendRev();
}

void WidgetComClient::setupConfigUI()
{

    pbtnAddOne = new QPushButton("添加");
    pbtnDeleteOne = new QPushButton("删除");
    pbtnApplyPLC = new QPushButton("应用");
    cbboxComNameList = new QComboBox();
    cbboxComTypeList = new QComboBox();

    cbboxComTypeList->addItems(ComBase::mapComClientTypeText.values());

    QFormLayout* fLayout = new QFormLayout();
    mLayout->addLayout(fLayout);

    QHBoxLayout* hLayout = new QHBoxLayout();
    fLayout->addRow(hLayout);
    hLayout->addWidget(pbtnAddOne);
    hLayout->addWidget(pbtnDeleteOne);
    hLayout->addWidget(pbtnApplyPLC);
    fLayout->addRow("通讯列表", cbboxComNameList);
    fLayout->addRow("协议类型", cbboxComTypeList);

    {
        //串口区域
        wgtSerialConfig = new QWidget();
        fLayout->addRow(wgtSerialConfig);
        QFormLayout* fSerialLayout = new QFormLayout();
        wgtSerialConfig->setLayout(fSerialLayout);
        cbboxSerialList = new QComboBox();
        cbboxSerialBaudRate = new QComboBox();
        cbboxSerialDataBits = new QComboBox();
        cbboxSerialParity = new QComboBox();
        cbboxSerialStopBits = new QComboBox();
        cbboxSerialFlowControl = new QComboBox();

        const auto infos = QSerialPortInfo::availablePorts();
        QStringList list;
        for (const QSerialPortInfo &info : infos) {
            list << info.portName();
        }
        cbboxSerialList->addItems(list);

        cbboxSerialBaudRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
        cbboxSerialBaudRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
        cbboxSerialBaudRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
        cbboxSerialBaudRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);

        cbboxSerialDataBits->addItem(QStringLiteral("5"), QSerialPort::Data5);
        cbboxSerialDataBits->addItem(QStringLiteral("6"), QSerialPort::Data6);
        cbboxSerialDataBits->addItem(QStringLiteral("7"), QSerialPort::Data7);
        cbboxSerialDataBits->addItem(QStringLiteral("8"), QSerialPort::Data8);
        cbboxSerialDataBits->setCurrentIndex(3);

        cbboxSerialParity->addItem(tr("None"), QSerialPort::NoParity);
        cbboxSerialParity->addItem(tr("Even"), QSerialPort::EvenParity);
        cbboxSerialParity->addItem(tr("Odd"), QSerialPort::OddParity);
        cbboxSerialParity->addItem(tr("Mark"), QSerialPort::MarkParity);
        cbboxSerialParity->addItem(tr("Space"), QSerialPort::SpaceParity);

        cbboxSerialStopBits->addItem(QStringLiteral("1"), QSerialPort::OneStop);
        #ifdef Q_OS_WIN
        cbboxSerialStopBits->addItem(tr("1.5"), QSerialPort::OneAndHalfStop);
        #endif
        cbboxSerialStopBits->addItem(QStringLiteral("2"), QSerialPort::TwoStop);

        cbboxSerialFlowControl->addItem(tr("None"), QSerialPort::NoFlowControl);
        cbboxSerialFlowControl->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);
        cbboxSerialFlowControl->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);

        fSerialLayout->addRow("串口号", cbboxSerialList);
        fSerialLayout->addRow("波特率", cbboxSerialBaudRate);
        fSerialLayout->addRow("数据位", cbboxSerialDataBits);
        fSerialLayout->addRow("校验", cbboxSerialParity);
        fSerialLayout->addRow("停止位", cbboxSerialStopBits);
        fSerialLayout->addRow("流控制", cbboxSerialFlowControl);
        wgtSerialConfig->setVisible(false);
    }
    {
        //网口区域
        wgtSocketConfig = new QWidget();
        fLayout->addRow(wgtSocketConfig);
        QFormLayout* fSocketLayout = new QFormLayout();
        wgtSocketConfig->setLayout(fSocketLayout);
        ledtOpponentIP = new QLineEdit("127.0.0.1");
        spboxOpponentPort = new QSpinBox();
        ledtLocalIP = new QLineEdit("127.0.0.1");
        spboxLocalPort = new QSpinBox();

        spboxOpponentPort->setRange(0,100000);
        spboxLocalPort->setRange(0,100000);
        spboxOpponentPort->setValue(5000);
        spboxLocalPort->setValue(6000);

        fSocketLayout->addRow("本地IP", ledtLocalIP);
        fSocketLayout->addRow("本地端口", spboxLocalPort);
        fSocketLayout->addRow("对方IP", ledtOpponentIP);
        fSocketLayout->addRow("对方端口", spboxOpponentPort);
    }
    {
        //Udp发送方式
        wgtSendType = new QWidget();
        fLayout->addRow(wgtSendType);
        QFormLayout* fUdpLayout = new QFormLayout();
        wgtSendType->setLayout(fUdpLayout);
        cbboxUdpSendType = new QComboBox();
        cbboxUdpSendType->addItems(QStringList() << tr("单播") << tr("广播") << tr("组播"));
        fUdpLayout->addRow("发送方式", cbboxUdpSendType);
        wgtSendType->setVisible(false);
    }
    chkboxSendHex = new QCheckBox("发送十六进制");
    fLayout->addRow(chkboxSendHex);
}

void WidgetComClient::setupSendRev()
{
        //接收区
    chkboxIsDisplayData = new QCheckBox("显示数据");
    chkboxIsDisplayHex = new QCheckBox("显示十六进制");
    pbtnClear = new QPushButton("清空");
    txtedtDataRev = new QTextEdit();

    txtedtDataSend = new QTextEdit();
    pbtnSendData = new QPushButton("发送");

    QVBoxLayout* vLayout0 = new QVBoxLayout();
    {
        QHBoxLayout* hLayout1 = new QHBoxLayout();
        hLayout1->addWidget(chkboxIsDisplayData);
        hLayout1->addWidget(chkboxIsDisplayHex);
        hLayout1->addWidget(pbtnClear);
        vLayout0->addLayout(hLayout1);
    }
    vLayout0->addWidget(txtedtDataRev);
    vLayout0->addWidget(txtedtDataSend);
    vLayout0->addWidget(pbtnSendData);
    mLayout->addLayout(vLayout0);
}

void WidgetComClient::initConnection()
{
    connect(pbtnAddOne, &QAbstractButton::clicked, this, [&](){
        QString type = QInputDialog::getItem(this, "选择通讯协议", "通讯协议", ComBase::mapComClientTypeText.values(), 0, false);
        QString name = QInputDialog::getText(nullptr,"输入新增通信名称","名称");
        if(name.isEmpty() || type.isEmpty())
            return;
        ComClientConfig config = getConfig();
        config.name = name;
        config.type = ComClientType(ComBase::mapComClientTypeText.values().indexOf(type));
        emit sigAddOne(config);
    });
    connect(pbtnDeleteOne, &QAbstractButton::clicked, this, [&](){
        if(!(cbboxComNameList->count() > 0))
            return;
        QMessageBox msgBox(QMessageBox::Question, "提示","确认删除此通信吗?",
                           QMessageBox::Yes | QMessageBox::No);
        msgBox.button(QMessageBox::Yes)->setText("确认");
        msgBox.button(QMessageBox::No)->setText("取消");
        if(QMessageBox::No == msgBox.exec())
            return;
        mMapComClient.remove(cbboxComNameList->currentText());
        emit sigDeleteOne(cbboxComNameList->currentText());
        cbboxComNameList->removeItem(cbboxComNameList->currentIndex());
    });
    connect(pbtnApplyPLC, &QAbstractButton::clicked, this, &WidgetComClient::onSaveConfig);
    connect(cbboxComNameList, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &WidgetComClient::onComSelectChanged);
    connect(cbboxComTypeList, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](const int& index){
        ComClientType type = ComClientType(index);
        wgtSocketConfig->setVisible(type == CCT_Tcp || type == CCT_Udp);
        wgtSerialConfig->setVisible(type == CCT_Serial);
        wgtSendType->setVisible(type == CCT_Udp);
    });

    connect(pbtnClear, &QAbstractButton::clicked, this, [&](){
        txtedtDataRev->clear();
    });

    connect(pbtnSendData, &QAbstractButton::clicked, this, [&](){
        QString txtSend = txtedtDataSend->toPlainText();
        emit sigWriteData(txtSend);
    });
}

ComClientConfig WidgetComClient::getConfig()
{
    ComClientConfig config;
    config.name = cbboxComNameList->currentText();
    config.type = ComClientType(cbboxComTypeList->currentIndex());
    config.isSendHex = chkboxSendHex->isChecked();
    switch (config.type)
    {
    case CCT_Tcp:
    {
        TcpComConfig tcpCfg;
        tcpCfg.name = config.name;
        tcpCfg.mOpponentIP = ledtOpponentIP->text();
        tcpCfg.mOpponentPort = spboxOpponentPort->value();
        tcpCfg.mLocalIP = ledtLocalIP->text();
        tcpCfg.mLocalPort = spboxLocalPort->value();
        tcpCfg.mIsSendHex = chkboxSendHex->isChecked();
        config.tcp = tcpCfg;
    }
        break;
    case CCT_Serial:
    {
        SerialComConfig serialCfg;
        serialCfg.name = config.name;
        serialCfg.comId = cbboxSerialList->currentText();
        serialCfg.baudRate = cbboxSerialBaudRate->currentData().toInt();
        serialCfg.dataBits = static_cast<QSerialPort::DataBits>(cbboxSerialDataBits->currentData().toInt());
        serialCfg.parity = static_cast<QSerialPort::Parity>(cbboxSerialParity->currentText().toInt());
        serialCfg.stopBits = static_cast<QSerialPort::StopBits>(cbboxSerialStopBits->currentText().toInt());
        serialCfg.flowControl = static_cast<QSerialPort::FlowControl>(cbboxSerialFlowControl->currentText().toInt());
        config.serial = serialCfg;
    }
        break;
    case CCT_Udp:
    {
        UdpComConfig udpCfg;
        udpCfg.name = config.name;
        udpCfg.mOpponentIP = ledtOpponentIP->text();
        udpCfg.mOpponentPort = spboxOpponentPort->value();
        udpCfg.mLocalIP = ledtLocalIP->text();
        udpCfg.mLocalPort = spboxLocalPort->value();
        udpCfg.mSendType = UdpSendType(cbboxUdpSendType->currentIndex());
        udpCfg.mIsSendHex = chkboxSendHex->isChecked();
        config.udp = udpCfg;
    }
        break;
    default:
        break;
    }
    return config;
}

void WidgetComClient::onSaveConfig()
{
    ComClientConfig config = getConfig();
    // Utils::setConfig(config.name, QVariant::fromValue(config), "PLCSetting");
    emit sigConfigChanged(config);
}

void WidgetComClient::onComSelectChanged(const int& index)
{
    if(index < 0)
        return;
    ComClientConfig config = mMapComClient.value(cbboxComNameList->currentText())->mConfig;
    cbboxComTypeList->setCurrentIndex(config.type);
    chkboxSendHex->setChecked(config.isSendHex);
    ComClientType type = config.type;
    if(type == CCT_Tcp){
        ledtOpponentIP->setText(config.tcp.mOpponentIP);
        spboxOpponentPort->setValue(config.tcp.mOpponentPort);
        ledtLocalIP->setText(config.tcp.mLocalIP);
        spboxLocalPort->setValue(config.tcp.mLocalPort);
    }else if(type == CCT_Serial){
        cbboxSerialList->setCurrentIndex(cbboxSerialList->findText(config.serial.name));
        cbboxSerialBaudRate->setCurrentIndex(cbboxSerialBaudRate->findData(config.serial.baudRate));
        cbboxSerialDataBits->setCurrentIndex(cbboxSerialDataBits->findData(config.serial.dataBits));
        cbboxSerialParity->setCurrentIndex(cbboxSerialParity->findData(config.serial.parity));
        cbboxSerialStopBits->setCurrentIndex(cbboxSerialStopBits->findData(config.serial.stopBits));
        cbboxSerialFlowControl->setCurrentIndex(cbboxSerialFlowControl->findData(config.serial.flowControl));
    }else if(type == CCT_Udp){
        ledtOpponentIP->setText(config.udp.mOpponentIP);
        spboxOpponentPort->setValue(config.udp.mOpponentPort);
        ledtLocalIP->setText(config.udp.mLocalIP);
        spboxLocalPort->setValue(config.udp.mLocalPort);
        cbboxUdpSendType->setCurrentIndex(config.udp.mSendType);
    }
}
